package com.kaluli.project.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * 基本类型比较   实现 java.util.Comparator接口
 * 支持比较大小的数据类型有
 * boolean,byte,char,int,long,float,double及他们的包装类 + String,Date这几种类型 
 * 返回结果
 * 声明： -1=小于   0=等于  1=小于
 * boolean	-1 0 1	这里按照   true 在系统中相当于1 false在系统中相当于0来比较
 * byte		-1 0 1	这里按照 字节长度来比较
 * char		-1 0 1	比较字符的长度
 * int		-1 0 1	比较大小
 * long		-1 0 1	比较大小
 * float	-1 0 1 	比较大小
 * double	-1 0 1	比较大小
 * String	-N 0 N	比较字符串的所有长度，返回字符串的长度差距
 * Date		-1 0 1	比较时间的大小
 * 
 * 支持List对比   new ComparatorUtils(Entity.class,"对比的字段",false)  当第3个参数是false则使用降序   ture则相反
 *  ------------------------------------------------------
 *  tempList为一个实体类的List
 *	List<Entity> tempList = entityService.getAll();
 *	Entity为这个实体类
 *	Collections.sort(tempList, new ComparatorUtils(Entity.class,"对比的字段",false));
 *	执行完后，List就自动通过对比的字段自动变成排序好的了    如果第3个参数是true 则是升序   如果是false则相反
 *
 *
 * 支持数据与数据的对比
 *  ------------------------------------------------------
 * Date date1...
 * Date date2...
 * ...
 * ComparatorUtils cu = new ComparatorUtils();
 * cu.compareValues(date1.getTime(),date2.getTime());
 *
 *
 * 支持对象与对象的相同属性对比
 * Entity tempObj1。。。
 * Entity tempObj2。。。
 * tempObj1.setValue(111);
 * tempObj2.setValue(222);
 * ComparatorUtils cu = new ComparatorUtils(Entity.class,"value",false);
 * int rst = cu.compareEntity(tempObj1,tempObj2);
 * System.out.println(rst);  //-1
 */
public class ComparatorUtils implements Comparator<Object> {
	
	private Class<?> c;//要比较的类
	private String fieldName;//根据类的那个属性比较；
	private Field field;
	private String filedTypeName; //属性类型名称
	private boolean isAsc; //比较结果是升序 or倒序, true:根据类属性自然比较结果的升序排列, false:根据类属性自然比较结果的倒序排列
	private int asc;
	private final static Map<String, String> compareMethods;
	
	//静态代码块
	static{
		compareMethods = new HashMap<String, String>();
		// * boolean,byte,char,int,long,float,double及他们的包装类 + String,Date这几种类型 
		compareMethods.put("boolean", "compareBoolean");
		compareMethods.put("byte", "compareByte");
		compareMethods.put("char", "compareCharacter");
		compareMethods.put("character", "compareCharacter");
		compareMethods.put("int", "compareInteger");   
		compareMethods.put("integer", "compareInteger");   
		compareMethods.put("long", "compareLong");   
		compareMethods.put("float", "compareFloat");   
		compareMethods.put("double", "compareDouble");   
		compareMethods.put("string", "compareString");   
		compareMethods.put("date", "compareDate");   
		compareMethods.put("bigdecimal", "compareBigDecimal");
	}
	
	

	/**
	 * 构造函数
	 * @param c要比较的类
	 * @param fieldName类的某一属性名称
	 * @param isAsc是根据此属性升序排列 or倒序排列 :true为升序，false为倒序
	 * @throws Exception
	 */
	public ComparatorUtils(){
	}
	
	
	/**
	 * 不排序对比
	 * @param c
	 * @param fieldName
	 */
	public ComparatorUtils(Class<?> c,String fieldName) throws Exception{
		init(c,fieldName,false);
	}
	
	/**
	 * 排序对比
	 * @param c
	 * @param fieldName
	 * @param isAsc
	 * @throws Exception
	 */
	public ComparatorUtils(Class<?> c,String fieldName, boolean isAsc) throws Exception {   
		init(c,fieldName,isAsc);
	}
	
	private void init(Class<?> c,String fieldName, boolean isAsc) throws NoSuchFieldException, SecurityException{
		this.c = c;   
		this.fieldName = fieldName;   
		field = this.c.getDeclaredField(this.fieldName);   
		filedTypeName = field.getType().getSimpleName();   
		this.isAsc = isAsc;   
		if(this.isAsc) {   
		 asc = 1;   
		} else {   
		asc = -1;   
		}
	}
	
	
	
	/**
	 * 重写Comparator接口的 compare方法
	 */
	@Override
	public int compare(Object o1, Object o2) {
		
		return 0;
	}

	/**
	 * 两个相同的对象对比 或者 整个List按照对象排序  可以调用此方法
	 * @param o1    对象一
	 * @param o2  对象二
	 * @return  -1小雨  0等于  1大于 
	 */
	public int compareEntity(Object o1,Object o2) {
		int result = 0;
	try {   
		field.setAccessible(true); //破坏了private,另外一种方案是：调用属性的get方法，但必须保证要有规范的get方法   
		Object value1 = field.get(o1);   
		Object value2 = field.get(o2);   
		result = compareBasicData(value1, value2);   
		} 
	catch (Exception e) {   
		 e.printStackTrace();   
		}    
		 return result;
	}
	/**
	 * 只要是2个值相比， 则可以调用该方法
	 * @param o1    对象一
	 * @param o2  对象二
	 * @return  -1小雨  0等于  1大于
	 */
	public int compareValues(Object o1,Object o2) {
		int result = 0;
	try {   
		Object value1 = o1;   
		Object value2 = o2;   
		result = compareBasicData(value1, value2);   
		} 
	catch (Exception e) {   
		 e.printStackTrace();   
		}    
		 return result;
	}
	
	 /**  
	* 认为null是最小的  
	* @param value1  
	* @param value2  
	 * @return  
	 * @throws NoSuchMethodException   
	* @throws SecurityException   
	*/  
	 private int compareBasicData(Object value1, Object value2) throws Exception {   
		int result = 0;   
		if((value1 == null && value2 == null)) {   
		result = 0;   
		} else if(value1 == null) {   
		result = -1*asc; //null是最小的，返回1*asc,如果是升序，则1*asc=1,否则1*asc=-1   
		} else if(value2 == null) {   
		result = 1*asc;   
		} else if(value1.equals(value2)) {   
		result = 0;   
		} else {   
		Method method = this.getClass().getDeclaredMethod(compareMethods.get(filedTypeName.toLowerCase()), Object.class, Object.class);   
		result = (Integer)method.invoke(this, value1, value2);   
		}   
		return result*asc;   
	}   
	@SuppressWarnings("unused")   
	private int compareBoolean(final Object value1, final Object value2) {   
		Boolean v1 = (Boolean)value1;   
		Boolean v2 = (Boolean)value2;   
		return v1.compareTo(v2);   
		}   
	@SuppressWarnings("unused")   
	private int compareByte(final Object value1, final Object value2) {   
		Byte v1 = (Byte)value1;   
		Byte v2 = (Byte)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareCharacter(final Object value1, final Object value2) {   
		Character v1 = (Character)value1;   
		Character v2 = (Character)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareInteger(final Object value1, final Object value2) {   
		Integer v1 = (Integer)value1;   
		Integer v2 = (Integer)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareLong(final Object value1, final Object value2) {   
		Long v1 = (Long)value1;   
		Long v2 = (Long)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareFloat(final Object value1, final Object value2) {   
		Float v1 = (Float)value1;   
		Float v2 = (Float)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareDouble(final Object value1, final Object value2) {   
		Double v1 = (Double)value1;   
		Double v2 = (Double)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareDate(final Object value1, final Object value2) {   
		Date v1 = (Date)value1;   
		Date v2 = (Date)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareString(final Object value1, final Object value2) {   
		String v1 = (String)value1;   
		String v2 = (String)value2;   
		return v1.compareTo(v2);   
	}   
	@SuppressWarnings("unused")   
	private int compareBigDecimal(final Object value1, final Object value2) {   
		BigDecimal v1 = (BigDecimal)value1;   
		BigDecimal v2 = (BigDecimal)value2;   
		return v1.compareTo(v2);   
	}

}
